execl (path, name, msgfd, addressfd, responsefd, msg_txname, msg_sender, (domsg) ? "y" : "n", 0) char *path, *name, *msg_txname, *msg_sender; int msgfd, addressfd, responsefd;
Channel programs view themselves as relatively independent. Their goal in life is to perform the task of "channel fitting," sending mail from one channel (module) to another, possibly also sending mail in the reverse direction. Most channel programs just send mail from deliver to an outbound channel. Interaction with deliver is co-routined, so that it looks, to the channel program, like any other mail port. phone and slave are the only two programs that currently send in both directions.
Each program's pattern for doing the fitting entails accessing the same types of modules, using similar types of interactions.
A channel module has an I/O package, which is called by higher-level read-mail and write-mail packages. They are called by the the "fitting" module. Hence, a process which transfers mail in both directions between two channels "xx" and "yy" will have the basic modules relationships:
As mentioned above, channel programs commonly send only from the local machine's deliver program, through module (qu_), out to a destination channel.
Such channel programs will have the basic structure:
qu_io qu_rdmail qu2yy_send yy_wtmailyy_io
When a channel program is invoked by deliver, the argument list is as shown in the Synopsis. The msgfd is a read-only file descriptor on the message text. The addressfd is a read-only pipe for getting destination addresses from deliver. The responsefd is for sending dispositions back to deliver. The last two arguments are the "name" of the message (almost never useful) and the return address, if given, of the message sender. This last is often used by channels during submission of the message to the next site.
The argument list is hidden from channel programs, by mapping it into the qu_* calls.
The I/O, read-mail and write-mail modules for channels have standard, but not identical, calls. In particular, a given module might not have certain calls. Also, some calls have mutually exclusive return options. In addition, the permissible sequencing of calls may be different.
For example, the write-mail call that sends an address can send either of two positive responses: Address ok, or Message ok. The former means that only the address was sent and that the message text must be sent separately, when the address list is completed. The latter means that a copy of the entire message was sent. A channel that can return one of the two values MAY NOT EVER return the other. It is the responsibility of the xx2yy_send module to check for correct return values.
The reason for the differences is that different channels may have VERY different protocol characteristics. For example, the local channel expects completed delivery of the entire message for each addressee. Alternatively, the telephone and SMTP packages expect the address list for a message to be sent before the (one) copy of the message text.
For the currently implemented channels, the Local delivery channel expects text-writing calls after each address call. Most other channels expect addresses to be specified before text is sent. The independent local submission and pickup modules are list oriented, although submission can accept text-per-address, somewhat awkwardly. The deliver module (qu_) will handle either mode.
A channel module might go through several phases:
In many cases, particularly initializations, the module's calls for a phase are no-ops. However, they are included for completeness and to permit easy modification.
To callers, message initialization only requires passing a mode string (usually containing an "m" to indicate that the mail is for a mailbox, rather than a terminal) and a return address string.
Address passing entails iteratively passing a host/local address combination and retrieving a mmdf.h reply value for the address. The host portion may not be passed to the destination channel, as in the case of the local channel since there is no question for which host the address is intended. (This does not preclude the local address portion from containing additional host references, if the one receiving the address is a relay.)
Text transfer is essentially a stream file transfer, effected by repeated calls to pass successive chunks of the message.
The following are the calls from which a channel draws its instructions. No single module uses the entire set.
Session handling (in xx_io):
* xx_init Get ready to handle mail * xx_end End this session * xx_synch Re-join sub-machines * xx_sbinit Caller will be submitting mail * xx_sbend Done submitting mail * xx_pkinit Caller wishes to receive mail xx_pkkill Caller wishes to stop receiving
Receiving mail (in xx_rmail):
* xx_rinit Caller wishes to receive a message xx_rkill Terminate current message xx_rainit Caller ready to receive addresses * xx_radr Get an address * xx_rtinit Caller ready to receive text * xx_rtxt Get some message text xx_rtcpy Give me a handle to text copy
Sending mail (in xx_wtmail):
* xx_winit Caller ready to send a message xx_wkill Terminate current message * xx_wainit Get ready for addresses * xx_wadr Here is an address * xx_waend Done sending set of addresses * xx_wtinit Get ready for message text * xx_wtxt Here is some message text * xx_wtend End of message text
Basic I/O (in xx_io):
* xx_wrply Here is a reply * xx_rrply Get a reply * xx_wrec Here is a record/packet * xx_wstm Here is part of a stream of text * xx_rrec Get a record * xx_rsinit Prepare to read stream * xx_rstm Get part of a stream of text
Notes:
The asterisks indicate which calls currently are used by at least one channel.
A common calling sequence will comprise:
xx_init /* init for sending */ xx_winit /* init first message */ xx_wadr /* send first address */ xx_rrply /* address acceptable? */ xx_wadr /* second address... */ xx_rrply ... xx_waend /* no more addresses */ xx_wtinit /* message text next */ xx_wtxt /* send a chunk of it */ xx_wtxt /* another... */ ... xx_wtend /* no more message */ xx_rrply /* text accepted ok?*/ xx_winit /* next message... */ ... xx_sbend /* no more sending */ xx_end /* done with channel */
Note that the only direct user calls to the xx_io part of the module are for initialization. No record or stream calls are made directly.
The following shows what channel programs and modules exist and what their names are.
Notes:
phone dials out to the site containing ph_slave and invokes it. Ph_io is combined with ph_iouser or ph_ioslave to make a full I/O set.
mm_wtmail calls submit. mm_rdmail calls deliver (by default) in pickup mode. The default pickup program may be changed by altering the variable pathpkup[] in conf.c. The mm module is the user software interface to MMDF, for mail submission and POBox delivery (pickup).
Lo_wtmail effects actual mailbox-stuffing. It does not have an associated lo_io because it was not needed.